package com.chenbei.schedule.util;

import cn.hutool.core.util.StrUtil;
import com.chenbei.common.exception.LogicHandleException;
import com.chenbei.common.util.SpringBeanUtil;
import com.chenbei.schedule.domain.ScheduleJob;
import lombok.Data;
import org.quartz.JobExecutionContext;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MethodInvocationUtil {

    /**
     * 解析调用目标字符串
     */
    public static MethodInvocation parseInvokeTarget(ScheduleJob scheduleJob) {
        if (StrUtil.isNotBlank(scheduleJob.getInvokeMethod())) {
            String invokeTarget = scheduleJob.getInvokeMethod().trim();

            // 检查格式是否正确
            if (!invokeTarget.matches("^([\\w.]+)\\.(\\w+)\\(([\\w,]*)\\)$")) {
                throw new IllegalArgumentException("调用目标格式不正确: " + invokeTarget);
            }

            // 解析出类/bean名、方法名和参数
            int methodStart = invokeTarget.lastIndexOf('.');
            int paramStart = invokeTarget.indexOf('(', methodStart);

            String target = invokeTarget.substring(0, methodStart);
            String methodName = invokeTarget.substring(methodStart + 1, paramStart);
            String[] params = new String[]{};
            if (scheduleJob.getInvokeMethodParams() != null && !scheduleJob.getInvokeMethodParams().isEmpty()) {
                params = scheduleJob.getInvokeMethodParams().toArray(new String[0]);
            }

            return new MethodInvocation(target, methodName, params);
        }
        return null;
    }

    /**
     * 调用方法
     * @param invocation 方法调用实例
     */
    public static Object invokeMethod(MethodInvocation invocation, JobExecutionContext context, ScheduleJob job) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Object targetObject;

        // 判断是bean调用还是类调用
        if (isSpringBean(invocation.target)) {
            // 从Spring容器获取bean
            targetObject = SpringBeanUtil.getBean(invocation.target);
        } else {
            // 通过反射加载类
            Class<?> clazz = Class.forName(invocation.target);
            targetObject = SpringBeanUtil.getBean(clazz);
            if (targetObject == null) {
                targetObject = clazz.getDeclaredConstructor().newInstance();
            }
        }

        // 获取方法参数类型
        Class<?>[] paramTypes = new Class[invocation.params.length];
        Object[] paramValues = new Object[invocation.params.length];

        for (int i = 0; i < invocation.params.length; i++) {
            String param = invocation.params[i].trim();

            // 特殊参数处理：JobExecutionContext和ScheduleJob
            if ("JobExecutionContext".equals(param)) {
                paramTypes[i] = JobExecutionContext.class;
                paramValues[i] = context;
            } else if ("ScheduleJob".equals(param)) {
                paramTypes[i] = ScheduleJob.class;
                paramValues[i] = job;
            } else {
                // 默认按String处理
                paramTypes[i] = String.class;
                paramValues[i] = param;
            }
        }

        // 获取方法
        if (targetObject != null) {
            Method method = targetObject.getClass().getMethod(invocation.methodName, paramTypes);

            // 调用方法
            return method.invoke(targetObject, paramValues);
        } else {
            throw new LogicHandleException("无实例对象。类名:" + invocation.target);
        }
    }

    /**
     * 判断是否是Spring bean名称（简单判断，不含包名）
     */
    private static boolean isSpringBean(String target) {
        // 简单判断：如果目标不包含点，或者第一个字母小写，则认为是bean名称
        return !target.contains(".") || Character.isLowerCase(target.charAt(0));
    }

    @Data
    public static class MethodInvocation {

        private String target;

        private String methodName;

        private String[] params;

        public MethodInvocation(String target, String methodName, String[] params) {
            this.target = target;
            this.methodName = methodName;
            this.params = params;
        }
    }
}
